#include "Exceptions.h"
#include "Lights.h"

using namespace cagd;

DirectionalLight::DirectionalLight(
       GLenum light_index,
       const HCoordinate &position,
       const Color &ambient_intensity,
       const Color &diffuse_intensity,
       const Color &specular_intensity):
       _light_index(light_index),
       _position(position),
       _ambient_intensity(ambient_intensity),
       _diffuse_intensity(diffuse_intensity),
       _specular_intensity(specular_intensity)
{
    _ambient_black.r = _ambient_black.g = _ambient_black.b = 0.0; _ambient_black.a = 1.0;
    _default_black.r = _default_black.g = _default_black.b = _default_black.a = 0.0;

    glLightfv(light_index, GL_POSITION, &_position.x);

    SwitchLight(false);
}

void DirectionalLight::Enable()
{
    glEnable(_light_index);
}

void DirectionalLight::Disable()
{
    glDisable(_light_index);
}

void DirectionalLight::SwitchLight(GLboolean on)
{
    glLightfv(_light_index, GL_AMBIENT,  on ? &_ambient_intensity.r : &_ambient_black.r);
    glLightfv(_light_index, GL_DIFFUSE,  on ? &_diffuse_intensity.r : &_default_black.r);
    glLightfv(_light_index, GL_SPECULAR, on ? &_specular_intensity.r : &_default_black.r);
}

PointLight::PointLight(
        GLenum light_index,
        const HCoordinate &position,
        const Color &ambient_intensity,
        const Color &diffuse_intensity,
        const Color &specular_intensity,
        GLfloat constant_attenuation,
        GLfloat linear_attenuation,
        GLfloat quadratic_attenuation):
        DirectionalLight(
                light_index,
                position,
                ambient_intensity, diffuse_intensity, specular_intensity),
        _constant_attenuation(constant_attenuation),
        _linear_attenuation(linear_attenuation),
        _quadratic_attenuation(quadratic_attenuation)
{
    if (position.w == 0.0)
        throw Exception("PointLight::PointLight_-_Wrong_position.");

    glLightf(_light_index, GL_SPOT_CUTOFF,              180.0);
    glLightf(_light_index, GL_CONSTANT_ATTENUATION,     _constant_attenuation);
    glLightf(_light_index, GL_LINEAR_ATTENUATION,       _linear_attenuation);
    glLightf(_light_index, GL_QUADRATIC_ATTENUATION,    _quadratic_attenuation);
}

SpotLight::SpotLight(
        GLenum light_index,
        const HCoordinate &position,
        const Color &ambient_intensity,
        const Color &diffuse_intensity,
        const Color &specular_intensity,
        GLfloat constant_attenuation,
        GLfloat linear_attenuation,
        GLfloat quadratic_attenuation,
        const HCoordinate &spot_direction,
        GLfloat spot_cutoff,
        GLfloat spot_exponent):
        PointLight(
                light_index,
                position,
                ambient_intensity, diffuse_intensity, specular_intensity,
                constant_attenuation, linear_attenuation, quadratic_attenuation),
        _spot_direction(spot_direction),
        _spot_cutoff(spot_cutoff),
        _spot_exponent(spot_exponent)
{
    if (position.w == 0.0)
        throw Exception("SpotLight::SpotLight_-_Wrong_position");
    if (_spot_cutoff == 180.0)
        throw Exception("SpotLight::SpotLight_-_Wrong_spot_cutoff");

    glLightfv(_light_index, GL_SPOT_DIRECTION,  &_spot_direction.x);
    glLightfv(_light_index, GL_SPOT_CUTOFF,     &_spot_cutoff);
    glLightfv(_light_index, GL_SPOT_EXPONENT,   &_spot_exponent);
}
